﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using YasharEl.Infrastructure.EntityModel;
using NHibernate;
using NHibernate.Linq;
using System.Diagnostics.Contracts;

namespace YasharEl.Infrastructure.PersistenceModel.NHibernate
{
	public class NHibernateUnitOfWork : IUnitOfWork
    {
        #region Constructors

        public NHibernateUnitOfWork(ISession session)
		{
            Contract.Requires<ArgumentNullException>(session != null, "session could not be null.");

			this.Session = session;
		}

        #endregion

        #region Properties

        public ISession Session { get; private set; }

        #endregion

        #region IUnitOfWork Members

        public void Flush()
		{
			this.Session.Flush();
		}

        public EntityModel.ITransaction BeginTransaction()
		{
			return new NHibernateTransaction(
				this.Session.BeginTransaction()
				);
		}

        public void EndTransaction(EntityModel.ITransaction transaction)
		{
			if (transaction != null)
			{
				(transaction as IDisposable).Dispose();
				transaction = null;
			}
		}

        public void Insert<TEntity, TIdentity>(TEntity entity) where TEntity : class, IGenericEntity<TIdentity>
		{
			this.Session.Save(entity);
		}

        public void Update<TEntity, TIdentity>(TEntity entity) where TEntity : class, IGenericEntity<TIdentity>
		{
			this.Session.Update(entity);
		}

        public void Delete<TEntity, TIdentity>(TEntity entity) where TEntity : class, IGenericEntity<TIdentity>
		{
			this.Session.Delete(entity);
		}

        public TEntity GetById<TEntity, TIdentity>(TIdentity id) where TEntity : class, IGenericEntity<TIdentity>
		{
			return this.Session.Get<TEntity>(id);
		}

        public IList<TEntity> GetAll<TEntity, TIdentity>() where TEntity : class, IGenericEntity<TIdentity>
		{
			return this.Session.CreateCriteria<TEntity>().List<TEntity>();
		}

        public IQueryable<TEntity> ToQueryable<TEntity, TIdentity>() where TEntity : class, IGenericEntity<TIdentity>
        {
            return this.Session.Query<TEntity>();//For NH3
        }

        public void ExecuteTransactional(Action action)
        {
            var transaction = Session.BeginTransaction();
            try
            {
                action();
                transaction.Commit();
            }
            catch (Exception)
            {
                transaction.Rollback();
                throw;

            }
            finally
            {
                transaction.Dispose();
            }
        }
	    #endregion

		#region IDisposable Members

		public void Dispose()
		{
			if ( this.Session != null )
			{
				(this.Session as IDisposable).Dispose();
				this.Session = null;
			}
		}

		#endregion
	}
}
